package com.easy.common.es.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.easy.common.core.domain.ESProperties;
import com.easy.common.core.domain.model.ESHouseInfo;
import com.easy.common.es.ESHouseService;
import com.easy.common.exception.UtilException;
import com.easy.common.utils.ip.AddressUtils;
import com.easy.common.utils.uuid.SnowFlake;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

@Service
public class ESHouseServiceImpl implements ESHouseService {
    private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
    @Autowired
    private RestHighLevelClient client;

    @Value("${es.indexes}")
    private String indexes;//索引

    @Value("${es.highlight}")
    private boolean highlight;
    @Autowired
    private ESProperties esProperties;

    @Override
    public void addDoc(ESHouseInfo esHouseInfo) {
//        SnowFlake snowFlake = new SnowFlake(11, 1);
//        IndexRequest request = new IndexRequest(indexes).id(String.valueOf(snowFlake.nextId()));//http://localhost:9200/HouseRent/_doc/1
        IndexRequest request = new IndexRequest(indexes);
        String json = JSON.toJSONString(esHouseInfo);
        request.source(json, XContentType.JSON);
        try {
            client.index(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new UtilException("ES iO流异常");
        }
    }

    @Override
    public void deleteDoc(ESHouseInfo houseInformation) {
        DeleteRequest deleteRequest = new DeleteRequest(indexes).id(String.valueOf(houseInformation.getId()));
        DeleteResponse deleteResponse = null;
        try {
            deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
            log.info("delete_doc_status：" + deleteResponse.status());
        } catch (IOException e) {
            throw new UtilException("ES iO流异常：" + deleteResponse.status());
        }

    }

    @Override
    public void batchAddDoc(List<ESHouseInfo> esHouseInfoList) {

    }

    @Override
    public void batchUpdateDoc(List<ESHouseInfo> esHouseInfoList) {

    }

    @Override
    public void updateDoc(ESHouseInfo esHouseInfo) {
        // 1构建请求
        UpdateRequest request = new UpdateRequest(indexes, String.valueOf(esHouseInfo.getId()));
        Map<String, Object> jsonMap = new HashMap<>();
        jsonMap.put("title", esHouseInfo.getTitle());
        jsonMap.put("price", esHouseInfo.getPrice());
        jsonMap.put("house_type", esHouseInfo.getHouse_type());
        jsonMap.put("area_size", esHouseInfo.getArea_size());
        jsonMap.put("location", esHouseInfo.getLocation());
        jsonMap.put("type", esHouseInfo.getType());
        jsonMap.put("img", esHouseInfo.getImg());
        request.doc(jsonMap);

        //超时时间
        request.timeout("2s");
        //重试次数
        request.retryOnConflict(3);
        UpdateResponse updateResponse = null;
        try {
            updateResponse = client.update(request, RequestOptions.DEFAULT);
            log.info("update_doc_status：" + updateResponse.status());
        } catch (IOException e) {
            throw new UtilException("ES iO流异常：" + updateResponse.status());
        }
    }

    @Override
    public List<ESHouseInfo> queryDocByCondition(String name, String msg) {
        SearchRequest request = new SearchRequest(indexes);

        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.termQuery(name, msg));
        request.source(builder);

        SearchResponse response = null;
        List<ESHouseInfo> doc = new ArrayList<>();
        try {
            response = client.search(request, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                String source = hit.getSourceAsString();
                ESHouseInfo esHouseInfo = JSON.parseObject(source, ESHouseInfo.class);
                doc.add(esHouseInfo);
            }
        } catch (IOException e) {
            throw new UtilException("ES iO流异常");
        }
        return doc;
    }

    @Override
    public JSONObject conditionalPaginationQuery(int page, int pageSize, String name, String value) {
        // 1.创建检索请求
        SearchRequest searchrequest = new SearchRequest(indexes);
        // 2.创建条件构建器 SearchSourceBuilder
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //因为Obj不能直接转成int所以要做一下处理
        // 3.符合查询条件
        if (value != null && value != "") {
            //构建查询条件
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            //符合查询用bool         must代表必须满足   matchQuery匹配
            BoolQueryBuilder must = boolQueryBuilder.must(QueryBuilders.matchQuery(name, value).fuzziness(Fuzziness.ONE));

            //执行查询条件
            builder.query(must);
        }
        // 4.分页
        builder.from((page - 1) * pageSize);
        builder.size(pageSize);
        builder.sort("w", SortOrder.DESC);// 权重

        // 设置高亮
        if (highlight) {
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            for (String s : esProperties.getHighlightField()) {
                highlightBuilder.field(s);
            }
            highlightBuilder.preTags("<font color='red'>");
            highlightBuilder.postTags("</font>");
            builder.highlighter(highlightBuilder);
        }


        // 5.查询条件构建器
        searchrequest.source(builder);
        SearchResponse search = null;
        try {
            search = client.search(searchrequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new UtilException("ES iO流异常");
        }

        // 6.查询，获取搜索结果
        SearchHits hits = search.getHits();
        long total = hits.getTotalHits().value;

        // 7.获取hits数组
        SearchHit[] hits1 = hits.getHits();
        List<JSONObject> arr = new ArrayList<>();
        JSONObject jsonObject = new JSONObject();// 作为结果返回数据
        for (SearchHit searchHit : hits1) {
            JSONObject json = new JSONObject();
            //获取到hits中的每一个asString
            String sourceAsString = searchHit.getSourceAsString();
            JSONObject records = JSONObject.parseObject(sourceAsString);
            String id = searchHit.getId();
            json.put("_records", records);
            json.put("_id", id);
            arr.add(json);
        }
/*
{
  "_index" : "house_rent_es",
  "_type" : "_doc",
  "_id" : "822133305667620864",
  "_score" : null,
  "_source" : {
    "area_size" : "190",
    "house_type" : "3室2厅2卫",
    "id" : 804444873503936512,
    "img" : "792786655790895104",
    "location" : "银海金海岸",
    "price" : "2000",
    "title" : "短租壹海江山海景房前排无遮挡看海33333333",
    "type" : "普通住宅",
    "w" : "0.0"
  },
  "sort" : [
    "0.0"
  ]
}        */


        jsonObject.put("total", Math.toIntExact(total));//总条数
        jsonObject.put("size", pageSize);//页面数量
        jsonObject.put("current", page);//当前页
        jsonObject.put("records", arr);//数据

        // 8.返回分页查询结果
        return jsonObject;
    }

    public void fuzzyQueryDocuments(String name, String value) throws IOException {

        // 构建查询的请求体
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //Damerau发现 80% 的人类拼写错误的编辑距离都是1. 换句话说, 80% 的拼写错误都可以通过 单次编辑修改为原始的字符串.
        sourceBuilder.query(QueryBuilders.fuzzyQuery(name, value).fuzziness(Fuzziness.ONE));
        //发送请求，获得结果
//        searchFunction(client,request,sourceBuilder);
        SearchRequest request = new SearchRequest("books");//索引

        //客户端发送请求，获取响应对象
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        // 打印响应结果
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            System.out.println(hit);
        }
    }

    public void page() {

    }

    @Override
    public String queryDocById(String id) {
        GetRequest request = new GetRequest(indexes, id);
        GetResponse response = null;
        String json;
        try {
            response = client.get(request, RequestOptions.DEFAULT);
            json = response.getSourceAsString();
        } catch (IOException e) {
            throw new UtilException("ES iO流异常");
        }
        return json;
    }

    @Override
    public void insert() {

    }


}
